﻿#include "channelitemmodel.h"
#include <QtMath>
#include <librtc.h>
#include "channelinfo.h"
#include "globaltools.h"
#include "protohash.h"
#include "servertimesync.h"

#define UNREAD_ROLE Qt::UserRole + 1

ChannelItemModel::ChannelItemModel(QObject *parent) : QAbstractListModel(parent)
{

}

static bool messageLessThan(const BaseChannelInfo *left, const BaseChannelInfo *right)
{
    //default/top/unread
    bool leftUnread = left->unread_count > 0, rightUnread = right->unread_count > 0;
    if(leftUnread != rightUnread)
        return leftUnread;
    return left->last_msg_time() > right->last_msg_time() ;
}


void ChannelItemModel::set_channel_list(QList<const BaseChannelInfo *> &const_channels)
{
    beginResetModel();
    std::sort(const_channels.begin(), const_channels.end(), messageLessThan);
    channel_list.swap(const_channels);
    endResetModel();
}

void ChannelItemModel::add_channel(const BaseChannelInfo *channel)
{
    auto it = std::lower_bound(channel_list.begin(), channel_list.end(), channel, messageLessThan);

    int toRow = it - channel_list.begin();

    beginInsertRows(QModelIndex(), toRow, toRow);
    channel_list.insert(it, channel);
    endInsertRows();
}

bool ChannelItemModel::isChannelHidden(int row, const QString &keyword) const
{
    if(keyword.isEmpty())
        return false;
    if(auto channel = channel_list.value(row, Q_NULLPTR))
        return !channel->display().contains(keyword, Qt::CaseInsensitive) && !QString::number(channel->id()).contains(keyword);
    return false;
}

void ChannelItemModel::maybeReordered(const BaseChannelInfo *channel)
{
    int row = channel_list.indexOf(channel);
    if(row >= 0)
    {
        if(checkOrder(row, channel))
        {
            QModelIndex index = createIndex(row, 0, channel->internalId());
            emit dataChanged(index, index);
        }
        else
        {
            auto temp = channel_list;
            if(row > 0)
                temp[row] = temp[row-1];
            else if(row < temp.size() - 1)
                temp[row] = temp[row + 1];
            auto it = std::lower_bound(temp.begin(), temp.end(), channel, messageLessThan);
            int toRow = it - temp.begin();

            beginMoveRows(QModelIndex(), row, row, QModelIndex(), toRow);
            channel_list.removeAt(row);
            channel_list.insert(std::lower_bound(channel_list.begin(), channel_list.end(), channel, messageLessThan), channel);
            endMoveRows();
        }
    }
}

void ChannelItemModel::maybeReordered(const QList<const BaseChannelInfo *> &channels)
{
    bool checkResult = true;

    int minRow = channel_list.count();
    quintptr minKey = 0;
    int maxRow = 0;
    quintptr maxKey = 0;

    for(auto channel : channels)
    {
        int row = channel_list.indexOf(channel);
        if(row >= 0)
        {
            checkResult &= checkOrder(row, channel);
            if(minKey == 0 || row < minRow)
            {
                minKey = channel->internalId();
                minRow = row;
            }
            if(maxKey == 0 || row > maxRow)
            {
                maxKey = channel->internalId();
                maxRow = row;
            }
        }
    }
    if(!checkResult)
    {
        beginResetModel();
        std::sort(channel_list.begin(), channel_list.end(), messageLessThan);
        endResetModel();
    }
    else if(minRow <= maxRow && minKey && maxKey)
        emit dataChanged(createIndex(minRow, 0, minKey), createIndex(maxRow, 0, maxKey));

}

void ChannelItemModel::emitDataChanged(const BaseChannelInfo *channel)
{
    int row = channel_list.indexOf(channel);
    if(row >= 0)
    {
        QModelIndex index = createIndex(row, 0, channel->internalId());
        emit dataChanged(index, index);
    }
}

void ChannelItemModel::emitDataChanged(const QList<const BaseChannelInfo *> &channels)
{
    int minRow = channel_list.count();
    quintptr minKey = 0;
    int maxRow = 0;
    quintptr maxKey = 0;

    for(auto channel : channels)
    {
        int row = channel_list.indexOf(channel);
        if(row >= 0)
        {
            if(minKey == 0 || row < minRow)
            {
                minKey = channel->internalId();
                minRow = row;
            }
            if(maxKey == 0 || row > maxRow)
            {
                maxKey = channel->internalId();
                maxRow = row;
            }
        }
    }
    if(minRow <= maxRow && minKey && maxKey)
            emit dataChanged(createIndex(minRow, 0, minKey), createIndex(maxRow, 0, maxKey));
}

int ChannelItemModel::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : channel_list.count();
}

QModelIndex ChannelItemModel::index(int row, int column, const QModelIndex &parent) const
{
    if (hasIndex(row, column, parent))
        return createIndex(row, column, channel_list.value(row)->internalId());
    return QModelIndex();
}

QVariant ChannelItemModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= channel_list.count())
        return QVariant();
    auto it = BaseChannelInfo::fromInternalId(index.internalId());
    if(!it)
        return QVariant();
    if(role == Qt::DisplayRole)
        return it->display();
    else if(role == Qt::EditRole)
    {
        QStringList result;
        auto last_time = it->last_msg_time();
        if(last_time > 0)
        {
            auto msgTime = QDateTime::fromMSecsSinceEpoch(last_time);
            auto curDate = QDateTime::currentDateTime();
            auto days = msgTime.daysTo(curDate);
            if(days < 1)
                result << msgTime.toString(QLatin1String("HH:mm"));
            else if(days == 1)
                result << QObject::trECSUTF8("昨天");
            else if(msgTime.date().year() == curDate.date().year())
                result << msgTime.toString(QLatin1String("MM/dd"));
            else
                result << msgTime.toString(QLatin1String("yyyy/MM/dd"));
            auto last_msg = it->last_msg();
            if(!last_msg.isEmpty())
            {
                result << it->last_msg();
                return result;
            }
        }
    }
    else if(role == Qt::DecorationRole)
    {
        return it->decoration();
    }
    else if(role == Qt::UserRole)
        return it->internalId();
    else if(role == UNREAD_ROLE)
        return it->unread_count;
    return QVariant();
}

Qt::ItemFlags ChannelItemModel::flags(const QModelIndex &index) const
{
    if (!index.isValid() || index.row() >= channel_list.count() || index.model() != this)
        return Qt::ItemIsDropEnabled; // we allow drops outside the items
    return Qt::ItemIsEnabled;
}

bool ChannelItemModel::checkOrder(int row, const BaseChannelInfo *channel) const
{
    if(row > 0 && channel->last_msg_time() > channel_list.value(row - 1)->last_msg_time())
        return false;
    if(row < channel_list.size() - 1 && channel->last_msg_time() < channel_list.value(row + 1)->last_msg_time())
        return false;
    return true;
}

ChannelItemDelegate::ChannelItemDelegate(QObject *parent) : QStyledItemDelegate(parent)
{

}

void ChannelItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_ASSERT(index.isValid());

    QStyleOptionViewItem opt = option;

    QPixmap pixmap = qvariant_cast<QPixmap>(index.data(Qt::DecorationRole));
    if (!pixmap.isNull())
    {
        opt.features |= QStyleOptionViewItem::HasDecoration;
        opt.decorationSize = pixmap.size() / pixmap.devicePixelRatio();
    }
    opt.features |= QStyleOptionViewItem::HasDisplay;
    opt.state &= ~QStyle::State_Selected;
    opt.styleObject = Q_NULLPTR;
    drawControl(&opt, painter, option.widget, pixmap, index);
}

#include <QPainter>

void ChannelItemDelegate::drawControl(const QStyleOptionViewItem *opt, QPainter *p, const QWidget *widget, const QPixmap &icon, const QModelIndex &index) const
{
    p->save();
    p->setClipRect(opt->rect);
    p->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);

    auto style = widget->style();
    QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, opt, widget);
    QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, opt, widget);

    // draw the background
    style->drawPrimitive(QStyle::PE_PanelItemViewItem, opt, p, widget);

    // draw the icon
    if(opt->features.testFlag(QStyleOptionViewItem::HasDecoration))
    {
        auto drawSize = icon.size().scaled(iconRect.size(), Qt::KeepAspectRatio);
        if(drawSize != iconRect.size())
        {
            auto center = iconRect.center();
            iconRect.setSize(drawSize);
            iconRect.moveCenter(center);
        }
        p->drawPixmap(iconRect.x() + (iconRect.width() - drawSize.width()) / 2, iconRect.y() + (iconRect.height() - drawSize.height()) / 2, drawSize.width(), drawSize.height(), icon);
        //在图标右上角绘制未读数量
        if(quint32 unread = index.data(UNREAD_ROLE).toUInt())
        {
            auto smallFont = opt->font;
            if(smallFont.pixelSize() == -1)
                smallFont.setPointSizeF(smallFont.pointSizeF() * 0.8);
            else
                smallFont.setPixelSize(smallFont.pixelSize() * 0.8);
            p->setFont(smallFont);

            QString number = unread > 999 ? "999+" : QString::number(unread);
            auto boundingRect = p->boundingRect(QRectF(iconRect), Qt::AlignCenter, number);
            auto boundingWidth = boundingRect.width(), boundingHeight = boundingRect.height();
            if(boundingWidth < boundingHeight)
                boundingWidth = boundingHeight;
            auto centerWidth = boundingWidth - boundingHeight;
            qreal radiux = qSqrt(2) * boundingHeight / 2;
            boundingRect.setHeight(radiux * 2);
            boundingRect.setWidth(radiux * 2 + centerWidth);
            boundingRect.moveTop(iconRect.top());
            boundingRect.moveRight(iconRect.right());
            QPen pen(Qt::white);
            pen.setWidth(2);
            p->setPen(pen);
            p->setBrush(QColor("#cc0000"));
            p->drawRoundedRect(boundingRect, radiux, radiux);
            p->drawText(boundingRect, Qt::AlignCenter, number);

            p->setFont(opt->font);
        }
    }

    // draw the text
    //将text区域分为三块
    QPalette::ColorGroup cg = opt->state & QStyle::State_Enabled
                          ? QPalette::Normal : QPalette::Disabled;
    if (cg == QPalette::Normal && !(opt->state & QStyle::State_Active))
        cg = QPalette::Inactive;

    QRect textPartRect;
    auto last_message = index.data(Qt::EditRole).toStringList();
    if(last_message.size() == 2)
    {
        p->setPen(opt->palette.color(cg, QPalette::Dark));
        p->drawText(textRect.left(), textRect.top(), textRect.width() - 2, textRect.height(), Qt::AlignVCenter | Qt::AlignRight | Qt::TextSingleLine, last_message.value(0), &textPartRect);
        p->drawText(textRect.left(), textRect.top() + textRect.height() / 2, textRect.width() - textPartRect.width(), textRect.height() / 2, Qt::AlignTop | Qt::AlignLeft | Qt::TextSingleLine, last_message.value(1));
    }

    if (opt->state & QStyle::State_Selected) {
        p->setPen(opt->palette.color(cg, QPalette::HighlightedText));
    } else {
        p->setPen(opt->palette.color(cg, QPalette::Text));
    }

    if(!textPartRect.isEmpty())
    {
        p->drawText(textRect.left(), textRect.top(), textRect.width() - textPartRect.width(), textRect.height() / 2, Qt::AlignBottom | Qt::AlignLeft | Qt::TextSingleLine, index.data(Qt::DisplayRole).toString());
    }
    else
    {
        p->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, index.data(Qt::DisplayRole).toString());
    }

    // draw the focus rect
    //不画焦点框

     p->restore();
}
